﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Text;
using System.Text;

namespace Alvin.Common.Utils
{
    public static class BarCodeUtil
    {
        private static readonly object Sync = new object();
        #region private static volatile fields

        private static volatile IBarCode _code39;
        private static volatile IBarCode _code39Full;
        private static volatile IBarCode _code128A;
        private static volatile IBarCode _code128B;
        private static volatile IBarCode _code128C;
        private static volatile IBarCode _codeEan128;
        #endregion

        #region public static properties

        /// <summary>
        /// 仅支持43个字符的编码
        /// </summary>
        public static IBarCode Code39
        {
            get
            {
                if (_code39==null)
                {
                    lock (Sync)
                    {
                        if (_code39==null)
                        {
                            _code39 = new BarCode39();
                        }
                    }
                }
                return _code39;
            }
        }


        /// <summary>
        /// 支持128个字符的编码
        /// </summary>
        public static IBarCode Code39Full
        {
            get
            {
                if (_code39Full == null)
                {
                    lock (Sync)
                    {
                        if (_code39Full == null)
                        {
                            _code39Full = new BarCode39Full();
                        }
                    }
                }
                return _code39Full;
            }
        }

        /// <summary>
        /// 标准数字和字母，控制符，特殊字符；
        /// </summary>
        public static IBarCode Code128A
        {
            get
            {
                if (_code128A == null)
                {
                    lock (Sync)
                    {
                        if (_code128A == null)
                        {
                            _code128A = new BarCode128A();
                        }
                    }
                }
                return _code128A;
            }
        }

        /// <summary>
        /// 标准数字和字母，小写字母，特殊字符；
        /// </summary>
        public static IBarCode Code128B
        {
            get
            {
                if (_code128B == null)
                {
                    lock (Sync)
                    {
                        if (_code128B == null)
                        {
                            _code128B = new BarCode128B();
                        }
                    }
                }
                return _code128B;
            }
        }

        /// <summary>
        /// [00]-[99]的数字对集合，共100个，即只能表示偶数位长度的数字。
        /// </summary>
        public static IBarCode Code128C
        {
            get
            {
                if (_code128C == null)
                {
                    lock (Sync)
                    {
                        if (_code128C == null)
                        {
                            _code128C = new BarCode128C();
                        }
                    }
                }
                return _code128C;
            }
        }

        /// <summary>
        /// [00]-[99]的数字对集合，共100个，即只能表示偶数位长度的数字。
        /// </summary>
        public static IBarCode CodeEan128
        {
            get
            {
                if (_codeEan128 == null)
                {
                    lock (Sync)
                    {
                        if (_codeEan128 == null)
                        {
                            _codeEan128 = new BarCodeEan128();
                        }
                    }
                }
                return _codeEan128;
            }
        }

        #endregion

        /// <summary>
        /// BarCode39 可表示43种字符包括[a-z][0-9][-, ., $, /, +, %,Sspace]
        /// 星号(*)作为起始和结束符
        /// 每个符号由9个部分表示，其中5部分为条另4部分为空白
        /// 9个部分中有三个是宽的，6个是窄的，两个符号的条码之间有一条空白的窄条
        /// </summary>
        private class BarCode39 : IBarCode
        {
            public virtual int Padding { get { return 3; } }

            public virtual int BarWidth { get { return 1; } }

            public virtual Image GetImage(string inputString, int width, int height)
            {
                return GetImage(inputString, width, height, CommentPosition.None, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, CommentPosition position, Font font)
            {
                return GetImage(inputString, width, height, position, font, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, CommentPosition position, Font font, string prefix)
            {
                return GetImage(inputString, width, height, position, font, prefix, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, CommentPosition position, Font font, string prefix, string sufix)
            {
                return GetImage(inputString, width, height, Padding, Padding, position, font, prefix, sufix);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft)
            {
                return GetImage(inputString, width, height, padLeft, CommentPosition.None, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font)
            {
                return GetImage(inputString, width, height, padLeft, position, font, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font, string prefix)
            {
                return GetImage(inputString, width, height, padLeft, position, font, prefix, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font, string prefix, string sufix)
            {
                return GetImage(inputString, width, height, padLeft, padLeft, position, font, prefix, sufix);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop)
            {
                return GetImage(inputString, width, height, padLeft, padTop, CommentPosition.None, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font)
            {
                return GetImage(inputString, width, height, padLeft, padTop, position, font, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font, string prefix)
            {
                return GetImage(inputString, width, height, padLeft, padTop, position, font, prefix, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font, string prefix, string sufix)
            {
                return GetImage(inputString, width, height, padLeft, padTop, padLeft, padTop, position, font, prefix, sufix);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom)
            {
                return GetImage(inputString, width, height, padLeft, padTop, padLeft, padTop, CommentPosition.None, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font)
            {
                return GetImage(inputString, width, height, padLeft, padTop, padLeft, padTop, position, font, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font, string prefix)
            {
                return GetImage(inputString, width, height, padLeft, padTop, padLeft, padTop, position, font, prefix, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font, string prefix, string sufix)
            {
                if (inputString == null) throw new ArgumentNullException("inputString");
                var f = font ?? new Font(new FontFamily(GenericFontFamilies.Monospace), 12);
                var fontHeight = (int)Math.Ceiling(f.Size);
                padLeft = padLeft < Padding ? Padding : padLeft;        //左边界
                padTop = padTop < Padding ? Padding : padTop;           //上边界
                padright = padright < Padding ? Padding : padright;     //右边界
                padbottom = padbottom < Padding ? Padding : padbottom;  //下边界
                var intSourceLength = inputString.Length;               //原字符串长度
                var codedString = GetString(inputString);
                var intEncodeLength = codedString.Length;               //编码后字符串长度
                var widLength = BarWidth*3;
                var narrowLength = BarWidth;                          //细BarCode 宽度
                var totalLength = ((intEncodeLength + 1) / 10) * (widLength * 3 + narrowLength * 7);
                var unit = (width - padLeft - padright) / totalLength;      //放大倍数
                if (unit <= 0) unit = 1;
                width = totalLength * unit + padLeft + padright;   //最后确定的宽度
                var barHeight = height - (padTop + padbottom);
                var x = padLeft;
                var y = padTop;
                switch (position)
                {
                    case CommentPosition.TopLeft:
                    case CommentPosition.TopCenter:
                    case CommentPosition.TopRight:
                        {

                            barHeight -= fontHeight;
                            y -= fontHeight;
                        } break;
                    case CommentPosition.BottomLeft:
                    case CommentPosition.BottomCenter:
                    case CommentPosition.BottomRight:
                        {
                            barHeight -= Padding;
                        } break;
                }
                //制作图片
                var objBitmap = new Bitmap(width, height);
                var objGraphics = Graphics.FromImage(objBitmap); //宣告GDI+绘图界面
                //填上底色
                objGraphics.FillRectangle(Brushes.White, 0, 0, objBitmap.Width, objBitmap.Height);


                if (position != CommentPosition.None)
                {
                    y = padTop + (int)FontUtil.EmSizeToPix(f.Size) + 2;
                    var content = string.Format("{0}{1}{2}", prefix, inputString, sufix);
                    objGraphics.DrawString(content, f, Brushes.Black, x, padTop);
                }
                for (var i = 0; i < intEncodeLength; i++) //依码画出Code39 BarCode
                {
                    var intBarWidth = (codedString[i] == '1' ? widLength : narrowLength) * unit;
                    objGraphics.FillRectangle(i % 2 == 0 ? Brushes.Black : Brushes.White, x, y, intBarWidth, barHeight);
                    x += intBarWidth;
                }

                return objBitmap;
            }

            public virtual string GetString(string inputString)
            {
                var intSourceLength = inputString.Length;
                var sb = new StringBuilder();
                sb.Append(Code39Codes.GetCode(Code39Codes.StartEnd)).Append(Code39Codes.Split);
                for (var i = 0; i < intSourceLength; i++)
                {
                    var c = inputString[i];
                    //檢查是否有非法字元
                    if (!Code39Codes.IsValid(c))
                    {
                        throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal character", c));
                    }
                    sb.Append(Code39Codes.GetCode(c)).Append(Code39Codes.Split);
                }
                sb.Append(Code39Codes.GetCode(Code39Codes.StartEnd));
                return sb.ToString();
            }
        }

        /// <summary>
        /// 而Full ASCII Code 39除上述标准型Code 39之44个字元外,再搭配,"/","%","$","+"等前置符号即可扩充成128个字元(含一个起始和结束字元).
        /// </summary>
        private class BarCode39Full : BarCode39
        {
            public override string GetString(string inputString)
            {
                var intSourceLength = inputString.Length;
                var sb = new StringBuilder();
                sb.Append(Code39Codes.GetCode(Code39Codes.StartEnd)).Append(Code39Codes.Split);
                for (var i = 0; i < intSourceLength; i++)
                {
                    var c = inputString[i];
                    //檢查是否有非法字元
                    if (!Code39Codes.IsValidFull(c))
                    {
                        throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal character", c));
                    }
                    sb.Append(Code39Codes.GetFullCode(c)).Append(Code39Codes.Split);
                }
                sb.Append(Code39Codes.GetCode(Code39Codes.StartEnd));
                return sb.ToString();
            }
        }

        private class BarCode128 : IBarCode
        {
            public virtual int BarWidth { get { return 1; } }
            public virtual int Padding { get { return 3; } }

            public virtual Image GetImage(string inputString, int width, int height)
            {
                return GetImage(inputString, width, height, CommentPosition.None, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, CommentPosition position, Font font)
            {
                return GetImage(inputString, width, height, position, font, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, CommentPosition position, Font font, string prefix)
            {
                return GetImage(inputString, width, height, position, font, prefix, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, CommentPosition position, Font font, string prefix, string sufix)
            {
                return GetImage(inputString, width, height, Padding, Padding, position, font, prefix, sufix);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft)
            {
                return GetImage(inputString, width, height, padLeft, CommentPosition.None, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font)
            {
                return GetImage(inputString, width, height, padLeft, position, font, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font, string prefix)
            {
                return GetImage(inputString, width, height, padLeft, position, font, prefix, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font, string prefix, string sufix)
            {
                return GetImage(inputString, width, height, padLeft, padLeft, position, font, prefix, sufix);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop)
            {
                return GetImage(inputString, width, height, padLeft, padTop, CommentPosition.None, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font)
            {
                return GetImage(inputString, width, height, padLeft, padTop, position, font, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font, string prefix)
            {
                return GetImage(inputString, width, height, padLeft, padTop, position, font, prefix, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font, string prefix, string sufix)
            {
                return GetImage(inputString, width, height, padLeft, padTop, padLeft, padTop, position, font, prefix, sufix);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom)
            {
                return GetImage(inputString, width, height, padLeft, padTop, padLeft, padTop, CommentPosition.None, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font)
            {
                return GetImage(inputString, width, height, padLeft, padTop, padLeft, padTop, position, font, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font, string prefix)
            {
                return GetImage(inputString, width, height, padLeft, padTop, padLeft, padTop, position, font, prefix, null);
            }

            public virtual Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font, string prefix, string sufix)
            {
                if (inputString == null) throw new ArgumentNullException("inputString");
                var f = font ?? new Font(new FontFamily(GenericFontFamilies.Monospace), 12);
                var fontHeight = (int)Math.Ceiling(f.Size);
                padLeft = padLeft < Padding ? Padding : padLeft;        //左边界
                padTop = padTop < Padding ? Padding : padTop;           //上边界
                padright = padright < Padding ? Padding : padright;     //右边界
                padbottom = padbottom < Padding ? Padding : padbottom;  //下边界
                var intSourceLength = inputString.Length;               //原字符串长度
                var codeString = GetString(inputString);
                var intEncodeLength = codeString.Length;    //编码后字符串长度
                var totalLength = intEncodeLength * BarWidth;
                var unit = (width - padLeft - padright) / totalLength;      //放大倍数
                if (unit <= 0) unit = 1;
                width = totalLength * unit + padLeft + padright;   //最后确定的宽度
                var barHeight = height - (padTop + padbottom);
                var x = padLeft;
                var y = padTop;
                switch (position)
                {
                    case CommentPosition.TopLeft:
                    case CommentPosition.TopCenter:
                    case CommentPosition.TopRight:
                        {

                            barHeight -= fontHeight;
                            y -= fontHeight;
                        } break;
                    case CommentPosition.BottomLeft:
                    case CommentPosition.BottomCenter:
                    case CommentPosition.BottomRight:
                        {
                            barHeight -= Padding;
                        } break;
                }
                //制作图片
                var objBitmap = new Bitmap(width, height);
                var objGraphics = Graphics.FromImage(objBitmap); //宣告GDI+绘图界面
                //填上底色
                objGraphics.FillRectangle(Brushes.White, 0, 0, objBitmap.Width, objBitmap.Height);
                if (position != CommentPosition.None)
                {
                    y = padTop + (int)FontUtil.EmSizeToPix(f.Size) + 2;
                    var content = string.Format("{0}{1}{2}", prefix, inputString, sufix);
                    objGraphics.DrawString(content, f, Brushes.Black, x, padTop);
                }
                var intBarWidth = BarWidth * unit;
                foreach (var c in codeString)
                {
                    objGraphics.FillRectangle(c == 'b' ? Brushes.Black : Brushes.White, x, y, intBarWidth, barHeight);
                    x += intBarWidth;
                }
                return objBitmap;
            }

            public virtual string GetString(string inputString)
            {
                var sb = new StringBuilder();
                var sum = 0;
                var code = Code128Codes.GetCodeACode(Code128Codes.StartA);
                sb.Append(code.Code);   //添加编码值
                sum += code.Id;     //累加起始位的Id值
                for (var i = 0; i < inputString.Length; i++)
                {
                    var str = inputString[i].ToString();
                    if (!Code128Codes.IsValidCodeAValue(str))
                    {
                        throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal string", str));
                    }
                    code = Code128Codes.GetCodeACode(str);
                    sb.Append(code.Code);       //添加编码值
                    sum += code.Id * (i + 1);     //累加每一位的Id值和其所在位的乘积
                }
                var mode = sum % Code128Codes.Mode;
                code = Code128Codes.GetCode(mode);  //获取校验位
                sb.Append(code.Code); //添加编码值
                code = Code128Codes.GetCodeACode(Code128Codes.Stop);    //获取停止位
                sb.Append(code.Code);
                return sb.ToString();
            }
        }

        private class BarCode128A : BarCode128
        {
            public override int BarWidth { get { return 1; } }
            public override int Padding { get { return 3; } }
            public override string GetString(string inputString)
            {
                var sb = new StringBuilder();
                var sum = 0;
                var code = Code128Codes.GetCodeACode(Code128Codes.StartA);
                sb.Append(code.Code);   //添加编码值
                sum += code.Id;     //累加起始位的Id值
                for (var i = 0; i < inputString.Length; i++)
                {
                    var str = inputString[i].ToString();
                    if (!Code128Codes.IsValidCodeAValue(str))
                    {
                        throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal string", str));
                    }
                    code = Code128Codes.GetCodeACode(str);
                    sb.Append(code.Code);       //添加编码值
                    sum += code.Id*(i + 1);     //累加每一位的Id值和其所在位的乘积
                }
                var mode = sum%Code128Codes.Mode;
                code = Code128Codes.GetCode(mode);  //获取校验位
                sb.Append(code.Code); //添加编码值
                code = Code128Codes.GetCodeACode(Code128Codes.Stop);    //获取停止位
                sb.Append(code.Code);
                return sb.ToString();
            }
        }

        private class BarCode128B : BarCode128
        {
            public override  string GetString(string inputString)
            {
                if (string.IsNullOrEmpty(inputString)) throw new ArgumentException("inputString can't be null or empty");
                var sb = new StringBuilder();
                var sum = 0;
                var code = Code128Codes.GetCodeBCode(Code128Codes.StartB);
                sb.Append(code.Code);   //添加编码值
                sum += code.Id;     //累加起始位的Id值
                for (var i = 0; i < inputString.Length; i++)
                {
                    var str = inputString[i].ToString();
                    if (!Code128Codes.IsValidCodeBValue(str))
                    {
                        throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal string", str));
                    }
                    code = Code128Codes.GetCodeBCode(str);
                    sb.Append(code.Code);       //添加编码值
                    sum += code.Id * (i + 1);     //累加每一位的Id值和其所在位的乘积
                }
                var mode = sum % Code128Codes.Mode;
                code = Code128Codes.GetCode(mode);  //获取校验位
                sb.Append(code.Code); //添加编码值
                code = Code128Codes.GetCodeBCode(Code128Codes.Stop);    //获取停止位
                sb.Append(code.Code);
                return sb.ToString();
            }
        }

        private class BarCode128C : BarCode128
        {
            public override string GetString(string inputString)
            {
                try
                {
                    if (string.IsNullOrEmpty(inputString)) throw new ArgumentException("inputString can't be null or empty");
                    var length = inputString.Length;
                    if (length % 2 != 0) throw new ArgumentException("inputString length should be even");
                    var sb = new StringBuilder();
                    var sum = 0;
                    var code = Code128Codes.GetCodeCCode(Code128Codes.StartC);
                    sb.Append(code.Code);   //添加编码值
                    sum += code.Id;     //累加起始位的Id值
                    for (var i = 0; i < length; i+=2)
                    {
                        var str = inputString[i].ToString()+inputString[i+1];
                        if (!Code128Codes.IsValidCodeCValue(str))
                        {
                            throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal string", str));
                        }
                        code = Code128Codes.GetCodeCCode(str);
                        sb.Append(code.Code);       //添加编码值
                        sum += code.Id * (i/2 + 1);     //累加每一位的Id值和其所在位的乘积
                    }
                    var mode = sum % Code128Codes.Mode;
                    code = Code128Codes.GetCode(mode);  //获取校验位
                    sb.Append(code.Code); //添加编码值
                    code = Code128Codes.GetCodeCCode(Code128Codes.Stop);    //获取停止位
                    sb.Append(code.Code);
                    return sb.ToString();
                }
                catch (Exception e)
                {
                    throw new Exception(e.Message,e);
                }
            }
        }

        private class BarCodeEan128 : BarCode128
        {
            public override string GetString(string inputString)
            {
                if (string.IsNullOrEmpty(inputString)) throw new ArgumentException("inputString can't be null or empty");
                var length = inputString.Length;
                if (length % 2 != 0) throw new ArgumentException("inputString length should be even");
                var sb = new StringBuilder();
                var sum = 0;
                var code = Code128Codes.GetCodeCCode(Code128Codes.StartC);
                sb.Append(code.Code);   //添加编码值
                sum += code.Id;     //累加起始位的Id值
                code = Code128Codes.GetCodeCCode(Code128Codes.Fnc1);
                sb.Append(code.Code);   //添加编码值
                sum += code.Id*1;     //累加控制位的Id值
                for (var i = 0; i < length; i += 2)
                {
                    var str = inputString[i].ToString() + inputString[i + 1];
                    if (!Code128Codes.IsValidCodeCValue(str))
                    {
                        throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal string", str));
                    }
                    code = Code128Codes.GetCodeCCode(str);
                    sb.Append(code.Code);       //添加编码值
                    sum += code.Id * (i/2 + 2);     //累加每一位的Id值和其所在位的乘积
                }
                var mode = sum % Code128Codes.Mode;
                code = Code128Codes.GetCode(mode);  //获取校验位
                sb.Append(code.Code); //添加编码值
                code = Code128Codes.GetCodeCCode(Code128Codes.Stop);    //获取停止位
                sb.Append(code.Code);
                return sb.ToString();
            }
        }

        private static class Code39Codes
        {
            private static readonly System.Collections.Hashtable Table =
                System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());

            private static readonly System.Collections.Hashtable Table2 =
                System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());

            /// <summary>
            /// 两个字符之间的分隔符
            /// </summary>
            public const string Split = "0";

            /// <summary>
            /// 起始和终止字符
            /// </summary>
            public const char StartEnd = '*';

            /// <summary>
            /// 获取当前字符的编码
            /// 如果字符不属于该编码的编码范围会抛出
            /// IllegalCharacterException异常。
            /// </summary>
            /// <param name="c"></param>
            /// <returns></returns>
            public static string GetCode(char c)
            {
                if (!IsValid(c))
                {
                    throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal character", c));
                }
                return Table[c] as string;
            }

            /// <summary>
            /// 检查一个简单编码方式的字符是否合法
            /// </summary>
            /// <param name="c"></param>
            /// <returns></returns>
            public static bool IsValid(char c)
            {
                return Table.ContainsKey(c);
            }

            /// <summary>
            /// 获取完全编码方式下字符的编码
            /// </summary>
            /// <param name="c"></param>
            /// <returns></returns>
            public static string GetFullCode(char c)
            {
                if (!IsValidFull(c))
                {
                    throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal character", c));
                }
                if (Table2.ContainsKey(c))
                {
                    var trans = Table2[c] as string;
                    var arr = trans.ToCharArray();
                    var sb = new StringBuilder();
                    sb.Append(GetCode(arr[0])).Append(Split).Append(GetCode(arr[1]));
                    return sb.ToString();
                }
                return Table[c] as string;
            }

            /// <summary>
            /// 检查全编码方式的字符是否合法
            /// </summary>
            /// <param name="c"></param>
            /// <returns></returns>
            public static bool IsValidFull(char c)
            {
                return Table.ContainsKey(c)||Table2.ContainsKey(c);
            }

            /// <summary>
            /// 初始化字符对应的编码映射
            /// </summary>
            static Code39Codes()
            {
                /**
                * 0   000110100  
                * 1   100100001  
                * 2   001100001  
                * 3   101100000
                * 4   000110001  
                * 5   100110000  
                * 6   001110000  
                * 7   000100101
                * 8   100100100  
                * 9   001100100  
                 * 
                * A   100001001  
                * B   001001001
                * C   101001000  
                * D   000011001  
                * E   100011000  
                * F   001011000
                * G   000001101  
                * H   100001100  
                * I   001001100  
                * J   000011100
                * K   100000011  
                * L   001000011  
                * M   101000010  
                * N   000010011
                * O   100010010  
                * P   001010010  
                * Q   000000111  
                * R   100000110
                * S   001000110  
                * T   000010110  
                * U   110000001  
                * V   011000001
                * W   111000000  
                * X   010010001  
                * Y   110010000  
                * Z   011010000
                * -   010000101  
                * .   110000100  
                *     011000100
                * $   010101000
                * /   010100010  
                * +   010001010  
                * %   000101010  
                * *   010010100 
                */

                Table.Add(' ', "011000100");/* 32*/
                Table.Add('0', "000110100");/*48 0*/
                Table.Add('1', "100100001");/*49 1*/
                Table.Add('2', "001100001");/*50 2*/
                Table.Add('3', "101100000");/*51 3*/
                Table.Add('4', "000110001");/*52 4*/
                Table.Add('5', "100110000");/*53 5*/
                Table.Add('6', "001110000");/*54 6*/
                Table.Add('7', "000100101");/*55 7*/
                Table.Add('8', "100100100");/*56 8*/
                Table.Add('9', "001100100");/*57 9*/
                Table.Add('A', "100001001");/*65 A*/
                Table.Add('B', "001001001");/*66 B*/
                Table.Add('C', "101001000");/*67 C*/
                Table.Add('D', "000011001");/*68 D*/
                Table.Add('E', "100011000");/*69 E*/
                Table.Add('F', "001011000");/*70 F*/
                Table.Add('G', "000001101");/*71 G*/
                Table.Add('H', "100001100");/*72 H*/
                Table.Add('I', "001001100");/*73 I*/
                Table.Add('J', "000011100");/*74 J*/
                Table.Add('K', "100000011");/*75 K*/
                Table.Add('L', "001000011");/*76 L*/
                Table.Add('M', "101000010");/*77 M*/
                Table.Add('N', "000010011");/*78 N*/
                Table.Add('O', "100010010");/*79 O*/
                Table.Add('P', "001010010");/*80 P*/
                Table.Add('Q', "000000111");/*81 Q*/
                Table.Add('R', "100000110");/*82 R*/
                Table.Add('S', "001000110");/*83 S*/
                Table.Add('T', "000010110");/*84 T*/
                Table.Add('U', "110000001");/*85 U*/
                Table.Add('V', "011000001");/*86 V*/
                Table.Add('W', "111000000");/*87 W*/
                Table.Add('X', "010010001");/*88 X*/
                Table.Add('Y', "110010000");/*89 Y*/
                Table.Add('Z', "011010000");/*90 Z*/
                Table.Add('_', "010000101");/*45 -*/
                Table.Add('.', "110000100");/*46 .*/
                Table.Add('$', "010101000");/*36 $*/
                Table.Add('/', "010100010");/*47 /*/
                Table.Add('+', "010001010");/*43 +*/
                Table.Add('%', "000101010");/*37 %*/
                Table.Add('*', "010010100");/*42 **/


                Table2.Add('!', "/A");/*33 /A*/
                Table2.Add('"', "/B");/*34 /B*/
                Table2.Add('#', "/C");/*35 /C*/
                Table2.Add('$', "/D");/*36 /D*/
                Table2.Add('%', "/E");/*37 /E*/
                Table2.Add('&', "/F");/*38 /F*/
                Table2.Add('\'', "/G");/*39 /G*/
                Table2.Add('(', "/H");/*40 /H*/
                Table2.Add(')', "/I");/*41 /I*/
                Table2.Add('*', "/J");/*42 /J*/
                Table2.Add('+', "/K");/*43 /K*/
                Table2.Add(',', "/L");/*44 /L*/
                Table2.Add('_', "/M");/*45 /M*/
                Table2.Add('.', "/N");/*46 /N*/
                Table2.Add('/', "/O");/*47 /O*/
                Table2.Add(':', "/Z");/*58 /Z*/
                Table2.Add(';', "%F");/*59 %F*/
                Table2.Add('<', "%G");/*60 %G*/
                Table2.Add('=', "%H");/*61 %H*/
                Table2.Add('>', "%I");/*62 %I*/
                Table2.Add('?', "%J");/*63 %J*/
                Table2.Add('@', "%V");/*64 %V*/
                Table2.Add('[', "%K");/*91 %K*/
                Table2.Add('\\', "%L");/*92 %L*/
                Table2.Add(']', "%M");/*93 %M*/
                Table2.Add('^', "%N");/*94 %N*/
                Table2.Add('-', "%O");/*95 %O*/
                Table2.Add('`', "%W");/*96 %W*/
                Table2.Add('a', "+A");/*97 +A*/
                Table2.Add('b', "+B");/*98 +B*/
                Table2.Add('c', "+C");/*99 +C*/
                Table2.Add('d', "+D");/*100 +D*/
                Table2.Add('e', "+E");/*101 +E*/
                Table2.Add('f', "+F");/*102 +F*/
                Table2.Add('g', "+G");/*103 +G*/
                Table2.Add('h', "+H");/*104 +H*/
                Table2.Add('i', "+I");/*105 +I*/
                Table2.Add('j', "+J");/*106 +J*/
                Table2.Add('k', "+K");/*107 +K*/
                Table2.Add('l', "+L");/*108 +L*/
                Table2.Add('m', "+M");/*109 +M*/
                Table2.Add('n', "+N");/*110 +N*/
                Table2.Add('o', "+O");/*111 +O*/
                Table2.Add('p', "+P");/*112 +P*/
                Table2.Add('q', "+Q");/*113 +Q*/
                Table2.Add('r', "+R");/*114 +R*/
                Table2.Add('s', "+S");/*115 +S*/
                Table2.Add('t', "+T");/*116 +T*/
                Table2.Add('u', "+U");/*117 +U*/
                Table2.Add('v', "+V");/*118 +V*/
                Table2.Add('w', "+W");/*119 +W*/
                Table2.Add('x', "+X");/*120 +X*/
                Table2.Add('y', "+Y");/*121 +Y*/
                Table2.Add('z', "+Z");/*122 +Z*/
                Table2.Add('{', "%P");/*123 %P*/
                Table2.Add('|', "%Q");/*124 %Q*/
                Table2.Add('}', "%R");/*125 %R*/
                Table2.Add('~', "%S");/*126 %S*/
            }
        }

        private static class Code128Codes
        {
            private static readonly System.Collections.Hashtable Table = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
            private static readonly System.Collections.Hashtable TableA = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
            private static readonly System.Collections.Hashtable TableB = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
            private static readonly System.Collections.Hashtable TableC = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());

            public const int Mode = 103;

            /// <summary>
            /// In Code A,B,C Id=102
            /// </summary>
            public const string Fnc1 = "FNC1";

            /// <summary>
            /// In Code A,B Id=97
            /// </summary>
            public const string Fnc2 = "FNC2";

            /// <summary>
            /// In Code A,B Id=96
            /// </summary>
            public const string Fnc3 = "FNC3";

            /// <summary>
            /// In Code A Id=101
            /// In Code B Id=100
            /// </summary>
            public const string Fnc4 = "FNC4";

            /// <summary>
            /// In Code A,B Id=98
            /// </summary>
            public const string Shift = "SHIFT";

            /// <summary>
            /// In Code A,B Id=106
            /// </summary>
            public const string Stop = "Stop";

            /// <summary>
            /// In Code B,C Id=101
            /// </summary>
            public const string CodeA = "CODEA";

            /// <summary>
            /// In Code A,C Id=100
            /// </summary>
            public const string CodeB = "CODEB";

            /// <summary>
            /// In Code A,B Id=99
            /// </summary>
            public const string CodeC = "CODEC";

            /// <summary>
            /// In Code A,B,C Id=103
            /// </summary>
            public const string StartA = "StartA";

            /// <summary>
            /// In Code A,B,C Id=104
            /// </summary>
            public const string StartB = "StartB";

            /// <summary>
            /// In Code A,B,C Id=105
            /// </summary>
            public const string StartC = "StartC";

            /// <summary>
            /// 通过Id获取编码，仅用于获取校验位
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public static CodeRow GetCode(int id)
            {
                return Table[id] as CodeRow;
            }

            #region CodeA

            public static bool IsValidCodeAValue(string str)
            {
                return TableA.ContainsKey(str);
            }

            public static CodeRow GetCodeACode(string str)
            {
                if (!IsValidCodeAValue(str))
                {
                    throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal string", str));
                }
                return TableA[str] as CodeRow;
            }

            #endregion

            #region CodeB

            public static bool IsValidCodeBValue(string str)
            {
                return TableB.ContainsKey(str);
            }

            public static CodeRow GetCodeBCode(string str)
            {
                if (!IsValidCodeBValue(str))
                {
                    throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal string", str));
                }
                return TableB[str] as CodeRow;
            }

            #endregion

            #region CodeC

            public static bool IsValidCodeCValue(string str)
            {
                return TableC.ContainsKey(str);
            }

            public static CodeRow GetCodeCCode(string str)
            {
                if (!IsValidCodeCValue(str))
                {
                    throw new IllegalCharacterException(string.Format("\"{0}\" is an illegal string", str));
                }
                return TableC[str] as CodeRow;
            }

            #endregion

            static Code128Codes()
            {
                var code = new CodeRow(0, " ", " ", "00", "21222", "bbsbbssbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(1, "!", "!", "01", "222122", "bbssbbsbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(2, "\"", "\"", "02", "222221", "bbssbbssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(3, "#", "#", "03", "121223", "bssbssbbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(4, "$", "$", "04", "121322", "bssbsssbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(5, "%", "%", "05", "131222", "bsssbssbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(6, "&", "&", "06", "122213", "bssbbssbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(7, "'", "'", "07", "122312", "bssbbsssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(8, "(", "(", "08", "132212", "bsssbbssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(9, ")", ")", "09", "221213", "bbssbssbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(10, "*", "*", "10", "221312", "bbssbsssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(11, "+", "+", "11", "231212", "bbsssbssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(12, ",", ",", "12", "112232", "bsbbssbbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(13, "-", "-", "13", "122132", "bssbbsbbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(14, ".", ".", "14", "122231", "bssbbssbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(15, "/", "/", "15", "113222", "bsbbbssbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(16, "0", "0", "16", "123122", "bssbbbsbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(17, "1", "1", "17", "123221", "bssbbbssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(18, "2", "2", "18", "223211", "bbssbbbssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(19, "3", "3", "19", "221132", "bbssbsbbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(20, "4", "4", "20", "221231", "bbssbssbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(21, "5", "5", "21", "213212", "bbsbbbssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(22, "6", "6", "22", "223112", "bbssbbbsbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(23, "7", "7", "23", "312131", "bbbsbbsbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(24, "8", "8", "24", "311222", "bbbsbssbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(25, "9", "9", "25", "321122", "bbbssbsbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(26, ":", ":", "26", "321221", "bbbssbssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(27, ";", ";", "27", "312212", "bbbsbbssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(28, "<", "<", "28", "322112", "bbbssbbsbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(29, "=", "=", "29", "322211", "bbbssbbssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(30, ">", ">", "30", "212123", "bbsbbsbbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(31, "?", "?", "31", "212321", "bbsbbsssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(32, "@", "@", "32", "232121", "bbsssbbsbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(33, "A", "A", "33", "111323", "bsbsssbbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(34, "B", "B", "34", "131123", "bsssbsbbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(35, "C", "C", "35", "131321", "bsssbsssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(36, "D", "D", "36", "112313", "bsbbsssbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(37, "E", "E", "37", "132113", "bsssbbsbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(38, "F", "F", "38", "132311", "bsssbbsssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(39, "G", "G", "39", "211313", "bbsbsssbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(40, "H", "H", "40", "231113", "bbsssbsbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(41, "I", "I", "41", "231311", "bbsssbsssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(42, "J", "J", "42", "112133", "bsbbsbbbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(43, "K", "K", "43", "112331", "bsbbsssbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(44, "L", "L", "44", "132131", "bsssbbsbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(45, "M", "M", "45", "113123", "bsbbbsbbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(46, "N", "N", "46", "113321", "bsbbbsssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(47, "O", "O", "47", "133121", "bsssbbbsbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(48, "P", "P", "48", "313121", "bbbsbbbsbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(49, "Q", "Q", "49", "211331", "bbsbsssbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(50, "R", "R", "50", "231131", "bbsssbsbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(51, "S", "S", "51", "213113", "bbsbbbsbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(52, "T", "T", "52", "213311", "bbsbbbsssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(53, "U", "U", "53", "213131", "bbsbbbsbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(54, "V", "V", "54", "311123", "bbbsbsbbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(55, "W", "W", "55", "311321", "bbbsbsssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(56, "X", "X", "56", "331121", "bbbsssbsbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(57, "Y", "Y", "57", "312113", "bbbsbbsbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(58, "Z", "Z", "58", "312311", "bbbsbbsssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(59, "[", "[", "59", "332111", "bbbsssbbsbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(60, "\\", "\\", "60", "314111", "bbbsbbbbsbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(61, "]", "]", "61", "221411", "bbssbssssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(62, "^", "^", "62", "431111", "bbbbsssbsbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(63, "_", "_", "63", "111224", "bsbssbbssss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(64, "NUL", "`", "64", "111422", "bsbssssbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(65, "SOH", "a", "65", "121124", "bssbsbbssss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(66, "STX", "b", "66", "121421", "bssbssssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(67, "ETX", "c", "67", "141122", "bssssbsbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(68, "EOT", "d", "68", "141221", "bssssbssbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(69, "ENQ", "e", "69", "112214", "bsbbssbssss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(70, "ACK", "f", "70", "112412", "bsbbssssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(71, "BEL", "g", "71", "122114", "bssbbsbssss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(72, "BS", "h", "72", "122411", "bssbbssssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(73, "HT", "i", "73", "142112", "bssssbbsbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(74, "LF", "j", "74", "142211", "bssssbbssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(75, "VT", "k", "75", "241211", "bbssssbssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(76, "FF", "l", "76", "221114", "bbssbsbssss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(77, "CR", "m", "77", "413111", "bbbbsbbbsbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(78, "SO", "n", "78", "241112", "bbssssbsbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(79, "SI", "o", "79", "134111", "bsssbbbbsbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(80, "DLE", "p", "80", "111242", "bsbssbbbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(81, "DC1", "q", "81", "121142", "bssbsbbbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(82, "DC2", "r", "82", "121241", "bssbssbbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(83, "DC3", "s", "83", "114212", "bsbbbbssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(84, "DC4", "t", "84", "124112", "bssbbbbsbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(85, "NAK", "u", "85", "124211", "bssbbbbssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(86, "SYN", "v", "86", "411212", "bbbbsbssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(87, "ETB", "w", "87", "421112", "bbbbssbsbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(88, "CAN", "x", "88", "421211", "bbbbssbssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(89, "EM", "y", "89", "212141", "bbsbbsbbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(90, "SUB", "z", "90", "214121", "bbsbbbbsbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(91, "ESC", "{", "91", "412121", "bbbbsbbsbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(92, "FS", "|", "92", "111143", "bsbsbbbbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(93, "GS", "}", "93", "111341", "bsbsssbbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(94, "RS", "~", "94", "131141", "bsssbsbbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(95, "US", "DEL", "95", "114113", "bsbbbbsbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(96, "FNC3", "FNC3", "96", "114311", "bsbbbbsssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(97, "FNC2", "FNC2", "97", "411113", "bbbbsbsbsss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(98, "SHIFT", "SHIFT", "98", "411311", "bbbbsbsssbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(99, "CODEC", "CODEC", "99", "113141", "bsbbbsbbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(100, "CODEB", "FNC4", "CODEB", "114131", "bsbbbbsbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(101, "FNC4", "CODEA", "CODEA", "311141", "bbbsbsbbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(102, "FNC1", "FNC1", "FNC1", "411131", "bbbbsbsbbbs");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(103, "StartA", "StartA", "StartA", "211412", "bbsbssssbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(104, "StartB", "StartB", "StartB", "211214", "bbsbssbssss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(105, "StartC", "StartC", "StartC", "211232", "bbsbssbbbss");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
                code = new CodeRow(106, "Stop", "Stop", "Stop", "2331112", "bbsssbbbsbsbb");
                Table.Add(code.Id, code); TableA.Add(code.CodeA, code); TableB.Add(code.CodeB, code); TableC.Add(code.CodeC, code);
            }
 
            
        }
        /// <summary>
        /// 存放编码
        /// </summary>
        private class CodeRow
        {
            public int Id { get; private set; }
            public string CodeA { get; private set; }
            public string CodeB { get; private set; }
            public string CodeC { get; private set; }
            public string BandCode { get; private set; }
            public string Code { get; private set; }

            /// <summary>
            /// Id  CodeA   CodeB   CodeC   BandCode   Code
            /// </summary>
            /// <param name="id"></param>
            /// <param name="codeA"></param>
            /// <param name="codeB"></param>
            /// <param name="codeC"></param>
            /// <param name="bandCode"></param>
            /// <param name="code"></param>
            public CodeRow(int id, string codeA, string codeB, string codeC, string bandCode, string code)
            {
                Id = id;
                CodeA = codeA;
                CodeB = codeB;
                CodeC = codeC;
                BandCode = bandCode;
                Code = code;
            }
        }
    }

    public interface IBarCode
    {
        /// <summary>
        /// 上下左右的边距
        /// </summary>
        int Padding { get; }

        /// <summary>
        /// 白条或者黑条的最小宽度
        /// </summary>
        int BarWidth { get; }

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, CommentPosition position,Font font);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <param name="prefix">条形码说明信息的前缀</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, CommentPosition position,Font font, string prefix);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <param name="prefix">条形码说明信息的前缀</param>
        /// <param name="sufix">条形码说明信息的后缀</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, CommentPosition position,Font font, string prefix,string sufix);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左边距</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左边距</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左边距</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <param name="prefix">条形码说明信息的前缀</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font, string prefix);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左边距</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <param name="prefix">条形码说明信息的前缀</param>
        /// <param name="sufix">条形码说明信息的后缀</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, CommentPosition position, Font font, string prefix, string sufix);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左右边距</param>
        /// <param name="padTop">上下边距</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, int padTop);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左右边距</param>
        /// <param name="padTop">上下边距</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左右边距</param>
        /// <param name="padTop">上下边距</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="prefix">条形码说明信息的前缀</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font, string prefix);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左右边距</param>
        /// <param name="padTop">上下边距</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <param name="prefix">条形码说明信息的前缀</param>
        /// <param name="sufix">条形码说明信息的后缀</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, int padTop, CommentPosition position, Font font, string prefix, string sufix);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左边距</param>
        /// <param name="padbottom">下边距</param>
        /// <param name="padTop">上边距</param>
        /// <param name="padright">右边距</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左边距</param>
        /// <param name="padbottom">下边距</param>
        /// <param name="padTop">上边距</param>
        /// <param name="padright">右边距</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左边距</param>
        /// <param name="padbottom">下边距</param>
        /// <param name="padTop">上边距</param>
        /// <param name="padright">右边距</param>
        /// <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <param name="prefix">条形码说明信息的前缀</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font, string prefix);

        /// <summary>
        /// 获取指定字符串的条形码
        /// </summary>
        /// <param name="inputString">字符串内容</param>
        /// <param name="width">条形码图形的宽度</param>
        /// <param name="height">条形码图形的高度</param>
        /// <param name="padLeft">左边距</param>
        /// <param name="padbottom">下边距</param>
        /// <param name="padTop">上边距</param>
        /// <param name="padright">右边距</param>
        ///  <param name="position">条形码信息说明的位置</param>
        /// <param name="font">条形码说明信息的字体</param>
        /// <param name="prefix">条形码说明信息的前缀</param>
        /// <param name="sufix">条形码说明信息的后缀</param>
        /// <returns>System.Drawing.Image</returns>
        System.Drawing.Image GetImage(string inputString, int width, int height, int padLeft, int padTop, int padright, int padbottom, CommentPosition position, Font font, string prefix, string sufix);
        
        /// <summary>
        /// 获取输入字符串编码后的字符串
        /// GetImage Method "GetImage" Relay on this method to get code string.
        /// </summary>
        /// <param name="inputString"></param>
        /// <returns></returns>
        string GetString(string inputString);
    }

    public class IllegalCharacterException:Exception
    {
        public IllegalCharacterException():base()
        {
            
        }

        public IllegalCharacterException(string message) : base(message)
        {
            
        }
    }
    /// <summary>
    /// 说明文字的位置
    /// </summary>
    public enum CommentPosition
    {
        /// <summary>
        /// 无
        /// </summary>
        None,
        /// <summary>
        /// 上左
        /// </summary>
        TopLeft,
        /// <summary>
        /// 上右
        /// </summary>
       TopRight,
        /// <summary>
        /// 上中
        /// </summary>
        TopCenter,
        /// <summary>
        /// 下右
        /// </summary>
        BottomRight,
        /// <summary>
        /// 下左
        /// </summary>
        BottomLeft,
        /// <summary>
        /// 下中
        /// </summary>
        BottomCenter

    }
}
